/**
 * Created by no1 on 2015/6/27.
 */
'use strict';
// 通用 function
var fs = require('fs');
var path = require('path');
var md5 = require('md5');
var request = require('koa-request');
var async_request = require('request');
var C = require('../config');
//var mysql=require('../o2o/mysql.js');
var thunkify = require('thunkify');
//var mongo = require('../common/mongo_db');
//exports.poiModel = mongo.poi;
//mongo.initDB();

var redis = require('redis');
var wrapper = require('co-redis');

var redisClient;
if (C.redis.unix_socket) { // Unix Socket 方式
  redisClient = redis.createClient(C.redis.unix_socket, C.redis.options);
} else { // TCP 方式
  redisClient = redis.createClient(C.redis.port, C.redis.host, C.redis.options);
}
var redisCo = wrapper(redisClient);
exports.redisCo = redisCo;

//exports.debugLog = console.log.bind(console);
if (C.env === 'development' || C.env === 'test') {
  exports.debugLog = console.log.bind(console);
} else {
  exports.debugLog = function () {
  }
}


var _ = require('underscore');
_.str = require('underscore.string');
_.v = require('validator');

Date.prototype.format = function (format) //author: meizz
{
  var o = {
    "M+": this.getMonth() + 1, //month
    "d+": this.getDate(),    //day
    "h+": this.getHours(),   //hour
    "m+": this.getMinutes(), //minute
    "s+": this.getSeconds(), //second
    "q+": Math.floor((this.getMonth() + 3) / 3),  //quarter
    "S": this.getMilliseconds() //millisecond
  };
  if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
    (this.getFullYear() + "").substr(4 - RegExp.$1.length));
  for (var k in o)if (new RegExp("(" + k + ")").test(format))
    format = format.replace(RegExp.$1,
      RegExp.$1.length == 1 ? o[k] :
        ("00" + o[k]).substr(("" + o[k]).length));
  return format;
};

Date.prototype.addDays = function (d) {
  this.setDate(this.getDate() + d);
};
/**
 * todo 添加多天
 * @param date
 * @param day
 * @returns {Date}
 */
exports.addDays = function (date, day) {
  // 86400000 = 24*60*60*1000
  return new Date(date.getTime() + (86400000 * day))
}

/**
 @todo 取得到秒的时间戳
 函数名：timestamp
 * 参数：无
 * 返回：当前时间的10位UNIX时间戳
 */
function timestamp() {
  return parseInt(new Date().getTime() / 1000);
}

exports.timestamp = timestamp;


//递归解析 I.cmd
function getCmd(I) {
  let cmd = isJson(I.cmd);
  delete I.cmd;
  if (cmd !== false) {
    for (var i in cmd) {
      if (typeof cmd[i] != "function") {
        I[i] = cmd[i];
      }
    }
  }
  if (!_.isEmpty(I.cmd)) {
    return getCmd(I);
  }
  return I;
}

exports.InitI = function (Env) {
  let I = {};
  //Env.request.req.headers['content-type'] === 'application/json'
  if (/application\/json/.test(Env.request.req.headers['content-type'])) {
    I = Env.request.body.fields;
    if (Env.params) {
      if (Env.params['apiVer']) {
        var pattern = /^v(\d+)$/gi;
        var tmpVer = pattern.exec(Env.params['apiVer']);
        if (tmpVer[1] == undefined) {
          I['apiVerNum'] = 1;
        } else {
          I['apiVerNum'] = tmpVer[1];
        }
      }
      if (Env.params['action']) {
        I['action'] = Env.params['action'];
      }
      if (Env.params['actionGroup']) {
        I['actionGroup'] = Env.params['actionGroup'];
      }
    }
    I['apiVerNum'] = I['apiVerNum'] || 1;
  }
  return I;
};

/**
 * 全局参数检测
 * @param env
 * @param actArray
 * @param I
 */
exports.Init = function*(Env, actArray, I) {
  //var I = {};
  // {request.body.fields:{},params:{},query:{}}
  if (_.isEmpty(I)) {
    I = Env.I;
  }

  // 递归 cmd 参数
  //I = getCmd(I);

  var errors = {};
  if (I) {
    if (actArray && actArray.length > 0) {
      var act = I.act;
      if (typeof  act === 'undefined') {
        errors.msg = 'act必须存在';
        errors.level = 3;
      } else if (actArray.indexOf(act) < 0) {
        errors.msg = '未定义的功能';
        errors.level = 3;
      }
    }
    //for (var i in I) {
    //    // act 参数存在,并且判断是大于0不超过2位的整数。
    //    if (_.v.isIn(i, ['act'])) {
    //        if (_.v.isInt(I[i])) {
    //            if (I[i] >= 99 || I[i] < 1) {
    //                errors.param = i;
    //                errors.msg = i + ' 参数超出取值范围';
    //                errors.level = 3;
    //                break;
    //            }
    //            if (!_.v.isIn(I[i], actArray)) {
    //                errors.param = i;
    //                errors.msg = '未定义的功能';
    //                errors.level = 3;
    //                break;
    //            }
    //
    //        } else {
    //            errors.param = i;
    //            errors.level = 3;
    //            errors.msg = i + ' 参数必须是整数';
    //            break;
    //        }
    //    }
    //}

    //
    var result = __inputValidate(I);
    if (result.errCode != 0) {
      errors.msg = result.errMsg;
      errors.level = 3;
    }

    if (!_.isEmpty(errors)) {
      I.errors = errors;
      console.log('[o2oService ERR] [%s] [%O]', new Date().format('yyyy-MM-dd hh:mm:ss'), I);
    }

    console.log('[o2oService INFO] [%s] [%O]', new Date().format('yyyy-MM-dd hh:mm:ss'), I);
    if (C.env != 'production') {
      console.log('[o2oService Input] [%O]', I);
    }
  }


  return I;
};

/**
 * TODO
 * 内部调用,输入检测
 * @param json
 * @private
 * @return {errCode:0, errMsg:xxx}
 */
function __inputValidate(json) {
  var list = [json];
  while (list.length > 0) {
    var obj = list.shift();
    var result = __singleValidate(obj);
    if (result.errCode != 0) {
      return result;
    }
    if (result.subDoc && result.subDoc.length > 0) {
      list = list.concat(list, result.sub);
    }
  }
  return {errCode: 0, errMsg: null};
}
/**
 * TODO
 * 内部调用,单个检测
 * @param obj
 * @private
 * @return {errCode:0,errMsg:'xxx', sub:[doc]}
 */
function __singleValidate(obj) {
  var subDoc = [];

  // pageSize ===================================
  var pageSize = obj.pageSize;
  if (typeof pageSize !== 'undefined') {
    if (typeof pageSize != 'number') {
      return {errCode: 1, errMsg: 'pageSize必须是number'};
    }
    if (pageSize < 1 || pageSize > 50) {
      return {errCode: 1, errMsg: 'pageSize取值范围[1,50]'};
    }
  }
  // page ===================================
  var page = obj.page;
  if (typeof page !== 'undefined') {
    if (typeof page != 'number') {
      return {errCode: 1, errMsg: 'page必须是number'};
    }
    if (page < 1) {
      return {errCode: 1, errMsg: 'page取值范围必须 >=1 '};
    }
  }

  // loc  ===================================
  // 判定 loc:[x1(number,-180~180), y(number,-90~90)]
  var loc = obj.loc;
  if (typeof loc !== 'undefined') {
    if (!Array.isArray(loc)) {
      return {errCode: 1, errMsg: 'loc 参数类型错误:应为2个元素的数组'};
    }
    if (loc.length !== 2) {
      return {errCode: 1, errMsg: 'loc 参数类型错误:应为2个元素的数组'};
    }
    // 经度判断
    var long = loc[0];
    if (typeof long != 'number') {
      return {errCode: 1, errMsg: 'loc 参数类型错误:经度不是数字'};
    }
    if (long > 180 || long < -180) {
      return {errCode: 1, errMsg: 'loc 参数类型错误:经度范围-180~180'};
    }
    // 纬度判断
    var lat = loc[1];
    if (typeof lat != 'number') {
      return {errCode: 1, errMsg: 'loc 参数类型错误:纬度不是数字'};
    }
    if (lat > 90 || lat < -90) {
      return {errCode: 1, errMsg: 'loc 参数类型错误:纬度范围-90~90'};
    }
  }

  // district ===================================
  var district = obj.district;
  //if (typeof district !== 'undefined') {
  //    if (!district) {
  //        return {errCode: 1, errMsg: 'district错误'};
  //    }
  //    //if (!district.loc) {
  //    //    return {errCode: 1, errMsg: 'district缺少loc'};
  //    //} else {
  //    //    subDoc.push(district.loc);
  //    //}
  //
  //    if (typeof district.name !== 'string') {
  //        return {errCode: 1, errMsg: 'district [name]错误'};
  //    }
  //
  //    if (typeof district.code !== 'number') {
  //        return {errCode: 1, errMsg: 'district [code]错误'};
  //    }
  //
  //    if (typeof district.code !== 'number') {
  //        return {errCode: 1, errMsg: 'district [code]错误'};
  //    }
  //
  //    if (district.pCode && typeof district.pCode !== 'number') {
  //        return {errCode: 1, errMsg: 'district [pCode]错误'};
  //    }
  //    var lvl = district.level;
  //    if (lvl) {
  //        if (typeof lvl !== 'number' || lvl < 0) {
  //            return {errCode: 1, errMsg: 'district.level 必须正整数'};
  //        }
  //    }
  //}

  // id ==================number
  var id = obj.id;
  if (typeof id !== 'undefined') {
    if (typeof id !== 'number' || id < 0) {
      return {errCode: 1, errMsg: 'id必须为正整数'};
    }
  }


  return {errCode: 0, errMsg: null, subDoc: subDoc};
}
/*
 isJson 尝试判断字符串是否为json类型。返回json对象或false
 */
function isJson(str) {
  try {
    return JSON.parse(str);
  } catch (e) {
    return false;
  }
}

exports.isJson = isJson;

/**
 cleanData 用于清除数据一些不要的项,于mongo返回的_id
 json  要清理的数据 (object)||array
 arr   要清理的项   ['_id']
 delboj 要清理的的对象 true
 */
function dataFilter(jsonData, arr, delboj) {

  for (var prop in jsonData) {
    innerloop:
      if (!!delboj) {
        for (var i of arr) {
          if (prop == i) {
            delete jsonData[prop];
            break innerloop;
          }
        }
      }
    if (typeof(jsonData[prop]) == 'object') {
      dataFilter(jsonData[prop], arr, delboj);
    }
    else {
      for (var i of arr) {
        if (prop == i) {
          delete jsonData[prop];
          break;
        }
      }
    }
  }
  return jsonData
}
exports.dataFilter = dataFilter;
/*
 @todo获取页面返回信息（返回对象）
 @status 状态码
 @msg  返回信息
 @level 返回信息等级
 @data 数据项（对象）
 200：成功
 300：成功,但无数据,主要用于多页操作时判断。
 400：参数错误/超出范围/不可识别的命令/不可预见的错误
 401：功能要求必须登录下调用，而此时未登录或未成功登录
 402：功能要求手机绑定的用户调用，此时应弹出绑定手机的对话框
 500：网络不给力

 */
/*
 @todo 拼接数据并返回给外部,
 */
exports.returnMsg = function (status, msg, level, data) {
  var returnData = {};
  returnData.status = status || 200;
  returnData.message = {
    msg: msg || "",
    level: level || 3,
    time: this.timestamp()
  };
  returnData.result = {};
  if (typeof data === "object" && data !== null) {
    returnData.result = data;
  }

  if (level == 4) { // 增加经验和悦币, msg 格式为: {e:-123,b:0,act:'点赞成功'}  【e:经验,b:悦币】
    returnData.message.msg = "";
    returnData.message.level = 3;
    if (typeof msg === "object") {
      var e = msg.e || 0;
      var b = msg.b || 0;
      if (e != 0 && b != 0) { //如果既传经验，也传悦币
        //格式: 经验 +10，悦币 +5
        returnData.message.msg = "经验 " + (e > 0 ? "+" : "") + e + "分，悦币 " + (b > 0 ? "+" : "");
      } else if (e != 0) { //只传经验
        //格式: 经验 +10
        returnData.message.msg = "经验 " + (e > 0 ? "+" : "") + e + "分";
      } else if (b != 0) {
        //格式: 悦币 +10
        returnData.message.msg = "悦币 " + (e > 0 ? "+" : "") + e;
      }

      // 插入动作
      if (returnData.message.msg != '' && msg.act != undefined) {
        //if (msg.act.sub(-2)!='成功'){
        //  msg.act=msg.act+'成功';
        //}

        returnData.message.msg = msg.act + ' ' + returnData.message.msg;
      }
      returnData.message.level = 4;
    }
  }

  if (C.env != 'production') {
    console.log('[RETURN] [%s] [%s]', returnData.status, returnData.message.msg);
  }
  return returnData;
};
/*
 @todo 返回DAO结构数据,内部调用
 */
exports.returnData = function (err, msg, data) {
  // error: 0 正常，1 错误无有效数据
  msg = msg || '';
  if (data) {
    return {
      error: err,
      msg: msg,
      data: data
    }
  } else {
    return {
      error: err,
      msg: msg
    }
  }
};

/*
 @todo 验证是否是手机号码
 */
exports.isMobile = function (mob) {
  if (mob > 19999999999 || mob < 13000000000) {
    return false;
  } else {
    return true;
  }
};

/*
 @todo 获取随机数
 @len 随机数位数
 */
exports.getRandom = function (len) {
  return Math.floor(Math.random() * (Math.pow(10, len) - Math.pow(10, len - 1)) + Math.pow(10, len - 1));
};

/*
 @todo 获取limit
 @page 第几页
 @pageSize 每页多少条
 @num 才多少条
 */
exports.getMonLimit = function* (page, pageSize, num) {
  for (let i = 1; i < 10000; i++) {
    if (page * pageSize < (num * (i))) {
      return (num * (i));
    }
  }
};


/**
 * todo 路由跳转
 * @param Env
 * @param actArray
 * @param action
 * @returns {*}
 */
exports.o2oAction1 = function* (Env, actArray, action) {
  Env.I = yield exports.Init(Env, actArray);
  if (Env.I.errors) {
    return exports.returnMsg(400, Env.I.errors.msg, Env.I.errors.level);
  } else {
    return yield action(Env);
  }
};

exports.o2oAction = function* (Env, actArray, action) {
  Env.I = yield exports.Init(Env, actArray);
  if (Env.I.errors) {
    return exports.returnMsg(400, Env.I.errors.msg, Env.I.errors.level);
  } else {
    return yield action(Env);
  }
};

/**
 * @todo Dispatcher间传送信息
 * @param  string  name  Dispatcher名字
 * @param  string  fun  方法名
 * @param  string  fields  方法参数
 */
let Dao = require('./dao');
let hasDis = false;
let daos = null;
exports.getDataFromDispatcher = function* (name, fun, fields, opt, opt1, opt2) {
  if (!hasDis || !daos) {
    daos = {};
    this.debugLog('没有分派器,正在创建!')
    for (let one in Dao) {
      if (one == 'DD') continue;
      if (one == 'permission' || one == 'user') {
        daos[one] = Dao[one];
        continue;
      }
      daos[one] = new Dao[one];
    }
    hasDis = true;
  }
  this.debugLog('已创建分派器!');
  name = name.replace(/Dispatcher/, '');
  /*
   let ret
   if (opt2)       ret = yield daos[name][fun](fields, opt, opt1, opt2);
   else if (opt1)  ret = yield daos[name][fun](fields, opt, opt1);
   else if (opt)   ret = yield daos[name][fun](fields, opt);
   else            ret = yield daos[name][fun](fields);
   */
  let ret = yield daos[name][fun](fields, opt, opt1, opt2);
  return ret;
}



